package handler

import (
	"errors"
	"github.com/dlclark/regexp2"
	"github.com/gin-gonic/gin"
	"happy-book/internal/domain"
	"happy-book/internal/service"
	"happy-book/internal/web/jwt"
	"happy-book/internal/web/request"
	"happy-book/internal/web/response"
	"net/http"
	"strconv"
	"time"
)

const (
	//邮箱正则表达式
	emailRegexPattern = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$"

	//密码正则表达式
	passwordRegexPattern = `^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{8,64}$`

	// UidKey user_id Key
	UidKey = "uid"
)

// UserHandler 用户请求处理器
type UserHandler struct {
	emailRegexExp    *regexp2.Regexp
	passwordRegexExp *regexp2.Regexp
	svc              *service.UserService
}

// NewUserHandler 构造函数
// 通过依赖注入UserService
func NewUserHandler(svc *service.UserService) *UserHandler {
	return &UserHandler{
		//对正则表达式进行预编译,提升校验速度
		emailRegexExp:    regexp2.MustCompile(emailRegexPattern, regexp2.None),
		passwordRegexExp: regexp2.MustCompile(passwordRegexPattern, regexp2.None),
		svc:              svc,
	}
}

// RegisterRoutes 注册路由
// 这是一种分散路由注册的方式
func (h *UserHandler) RegisterRoutes(server *gin.Engine) {
	userGroup := server.Group("/user") //使用分组注册,优化代码组织方式

	//用户注册
	userGroup.POST("/sign_up", h.SignUp)

	//用户登录
	userGroup.POST("/login", h.Login)

	//编辑用户信息
	userGroup.PUT("/edit", h.Edit)

	//查询用户信息
	userGroup.GET("/profile", h.Profile)
}

// SignUp 注册
func (h *UserHandler) SignUp(ctx *gin.Context) {
	//绑定请求参数
	var req request.SignUpReq
	err := ctx.Bind(&req)
	if err != nil {
		ERR(ctx, response.IllegalReq, response.IllegalReqMessage, nil)
		return
	}

	//校验邮箱
	isEmail, err := h.emailRegexExp.MatchString(req.Email)
	if err != nil {
		ERR(ctx, response.IllegalReq, response.IllegalReqMessage, nil)
		return
	}
	if !isEmail {
		ERR(ctx, response.BusinessError, "邮箱不合法", nil)
		return
	}

	//校验密码
	isPassword, err := h.passwordRegexExp.MatchString(req.Password)
	if err != nil {
		ERR(ctx, response.IllegalReq, response.IllegalReqMessage, nil)
		return
	}
	if !isPassword {
		ERR(ctx, response.BusinessError, "密码不合法", nil)
		return
	}

	if req.Password != req.ConfirmPassword {
		ERR(ctx, response.BusinessError, "两次输入的密码不相同", nil)
		return
	}

	//调用service层处理
	err = h.svc.SignUp(ctx.Request.Context(), &domain.User{Email: req.Email, Password: req.Password})
	if err != nil {
		if errors.Is(err, service.ErrDuplicatedEmail) {
			ERR(ctx, response.BusinessError, err.Error(), nil)
			return
		}
		ERR(ctx, response.InternalServerError, response.InternalServerErrorMessage, nil)
		return
	}

	//返回成功响应
	OK(ctx, "注册成功")
}

// Login 登录
func (h *UserHandler) Login(ctx *gin.Context) {
	//绑定请求参数
	var req request.LoginReq
	err := ctx.Bind(&req)
	if err != nil {
		ERR(ctx, response.IllegalReq, response.IllegalReqMessage, nil)
		return
	}

	//处理登录
	u, err := h.svc.Login(ctx.Request.Context(), req.Email, req.Password)
	if err != nil { //登录失败
		if errors.Is(err, service.ErrInvalidEmailOrPassword) {
			ERR(ctx, response.BusinessError, "用户名或密码错误，请确认后重试~", nil)
			return
		}
		ERR(ctx, response.InternalServerError, response.InternalServerErrorMessage, nil)
		return
	}

	//登录成功,生成JWT Token,并通过Response Header返回给前端
	token, err := jwt.GenerateLoginToken(ctx, u.Id)
	if err != nil {
		ERR(ctx, response.InternalServerError, response.InternalServerErrorMessage, nil)
		return
	}
	ctx.Header(jwt.TokenHeaderKey, token)
	OK(ctx, "登录成功")
}

// Edit 编辑用户信息
func (h *UserHandler) Edit(ctx *gin.Context) {
	userId := Uid(ctx)
	if userId <= 0 { //未登录,拒绝访问
		ctx.AbortWithStatus(http.StatusUnauthorized)
		return
	}

	//绑定请求参数
	var req request.EditReq
	err := ctx.Bind(&req)
	if err != nil {
		ERR(ctx, response.IllegalReq, response.IllegalReqMessage, nil)
		return
	}

	//校验请求参数
	nickname := req.Nickname
	if nickname == "" {
		ERR(ctx, response.IllegalReq, "昵称不能为空", nil)
		return
	}
	if len(nickname) > 64 {
		ERR(ctx, response.IllegalReq, "昵称过长", nil)
		return
	}
	aboutMe := req.AboutMe
	if aboutMe == "" {
		ERR(ctx, response.IllegalReq, "个人简介不能为空", nil)
		return
	}
	if len(aboutMe) > 1024 {
		ERR(ctx, response.IllegalReq, "个人简介过长", nil)
		return
	}

	birthday := req.Birthday
	_, err = time.Parse(time.DateOnly, req.Birthday)
	if err != nil {
		ERR(ctx, response.IllegalReq, "出生日期格式不正确", nil)
		return
	}

	//调用service层处理
	user := &domain.User{
		Id:       userId,
		Nickname: nickname,
		AboutMe:  aboutMe,
		Birthday: birthday,
	}
	err = h.svc.UpdateNonSensitiveInfo(ctx.Request.Context(), user)
	if err != nil {
		ctx.JSON(http.StatusOK, response.NewRestResp(response.InternalServerError, response.InternalServerErrorMessage, nil))
		return
	}
	OK(ctx, "修改个人信息成功")
}

// Profile 查看用户个人信息
func (h *UserHandler) Profile(ctx *gin.Context) {
	userId := Uid(ctx)
	if userId <= 0 { //未登录,拒绝访问
		ctx.AbortWithStatus(http.StatusUnauthorized)
		return
	}

	//查询用户信息
	user, err := h.svc.Profile(ctx.Request.Context(), userId)
	if err != nil {
		if errors.Is(err, service.ErrInvalidEmailOrPassword) { //用户不存在
			ERR(ctx, response.BusinessError, err.Error(), nil)
			return
		}
		ERR(ctx, response.InternalServerError, response.InternalServerErrorMessage, nil)
	}

	//返回用户信息
	resp := response.UserProfileResp{
		Id:       strconv.Itoa(int(user.Id)),
		Email:    user.Email,
		Nickname: user.Nickname,
		Birthday: user.Birthday,
		AboutMe:  user.AboutMe,
		Avatar:   user.Avatar,
	}
	OK(ctx, resp)
}
